Startup
library(tidyverse)
library(cowplot)
library(ggpmisc)
source("data_import_functions.R")
source("calculation_functions.R")
source("figure_format_functions.R")
all_hla_expanded <- readRDS("all_hla_expanded.RDS")
isb_path <- "/labs/khatrilab/solomonb/covid/isb"
isb_samples <- read_tsv("/labs/khatrilab/solomonb/covid/isb/logs/210217_232725/parallel.log") %>%
separate(Command, into = c(NA, "sample"), sep = " ") %>%
pull(sample) %>% unique()
Get reference alleles
reference_alleles <- read_tsv("GCh38_reference_alleles.txt", col_names = F) %>% pull(1)
genome_region_reference <- get_allele_length(reference_alleles)
Get arcasHLA alignment stats
arcas_log_dir <- sprintf("%s/arcasHLA", isb_path)
alignment_stats_df <- hla_mapping_stats_import(isb_samples, arcas_log_dir)
Import cell counts
cell_counts_df <- readRDS("isb_sequenced_cell_count.RDS")
Assemble accuracy DF
success_df <- readRDS("isb_success.RDS")
accuracy_df <- readRDS("isb_accuracy_drb345_filtered.RDS")
accuracy_df <- accuracy_df %>%
left_join(
success_df %>% select(sample:field, genotyper, success = accuracy),
by = c("sample", "locus", "field", "genotyper")
)%>%
left_join(alignment_stats_df, by = c("sample", "locus")) %>%
left_join(genome_region_reference, by = "locus") %>%
left_join(cell_counts_df, by = "sample") %>%
mutate_at(vars(c(reads, bp)), as.numeric) %>%
mutate(coverage = (reads * 91)/bp) %>%
mutate(n_alleles = map_dbl(allele, function(x) sum(!is.na(x)))) %>%
filter(grepl("^[ABC]|D.[AB]1", locus) & grepl("-(AC|BL)$", sample) & genotyper != "hlaminer")
Coverage based plots
gg_coverage(accuracy_df, x_var = "coverage", y_var = "accuracy")
`geom_smooth()` using formula 'y ~ x'

gg_coverage(accuracy_df, x_var = "coverage", y_var = "success")
`geom_smooth()` using formula 'y ~ x'

gg_coverage(accuracy_df, x_var = "coverage", y_var = "n_alleles", facet_genotyper = T)

Cell number based plots
gg_coverage(accuracy_df, x_var = "n_cells", y_var = "accuracy")
`geom_smooth()` using formula 'y ~ x'

gg_coverage(accuracy_df, x_var = "n_cells", y_var = "success")
`geom_smooth()` using formula 'y ~ x'

gg_coverage(accuracy_df, x_var = "n_cells", y_var = "n_alleles", facet_genotyper = T)

Subsample READS
Import read subsample data
# Import predicted genotypes
subsample_reads_path <- "/labs/khatrilab/solomonb/covid/isb/subsample"
subsample_reads_samples <- tibble(sample = list.files(sprintf("%s/arcasHLA", subsample_reads_path))) %>%
filter(grepl("^INCOV", sample)) %>%
separate(sample, into = c("sample"), sep = "\\.", extra = "drop") %>%
distinct() %>%
pull(sample)
subsample_reads_df <- format_hla_table(combine_HLA_import(path = subsample_reads_path, samples = subsample_reads_samples))
subsample_reads_df <- subsample_reads_df %>%
filter(grepl("^[ABC]|D.[AB]1", locus) & grepl("-(AC|BL)_", sample))
subsample_reads_df
# Expand invitro genotypes across read subsample names
invitro_df <- invitro_import()
Rows: 1557 Columns: 9
── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (8): Sample ID, Locus, Allele 1, Allele 2, Comments, Diploid Ambiguities, Allele 1 Ambiguities, Allele 2 Ambiguities
dbl (1): index
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
invitro_reads_df <- subsample_reads_df %>%
select(sample) %>%
distinct() %>%
separate(sample, into = c("sample", "subsample"), sep = "_") %>%
left_join(invitro_df, by = "sample") %>%
unite(sample, sample, subsample, sep = "_") %>%
format_hla_table() %>%
drop_na()
invitro_reads_df
# Import read statistics
subsample_reads_arcas_log_dir <- sprintf("%s/arcasHLA", subsample_reads_path)
subsample_reads_alignment_stats_df <- hla_mapping_stats_import(subsample_reads_samples, subsample_reads_arcas_log_dir)
Calculate accuracy
# Calculate accuracy
subsample_reads_accuracy_df <- compare_hla(
hla_df = bind_rows(
subsample_reads_df,
invitro_reads_df
),
reference = "invitro",
method = "accuracy"
)
# saveRDS(subsample_reads_accuracy_df, "isb_subsample_reads_accuracy.RDS")
# Calculate success
subsample_reads_success_df <- compare_hla(
hla_df = bind_rows(
subsample_reads_df,
invitro_reads_df
),
reference = "invitro",
method = "success"
)
# saveRDS(subsample_reads_success_df, "isb_subsample_reads_success.RDS")
# Combine various data
subsample_reads_combined_df <- subsample_reads_accuracy_df %>%
left_join(
subsample_reads_success_df %>% select(sample:field, genotyper, success = accuracy),
by = c("sample", "locus", "field", "genotyper")
)%>%
left_join(subsample_reads_alignment_stats_df, by = c("sample", "locus")) %>%
left_join(genome_region_reference, by = "locus") %>%
bind_rows(accuracy_df %>% select(-n_cells)) %>% # No cell numbers for read subsamples
mutate_at(vars(c(reads, bp)), as.numeric) %>%
mutate(coverage = (reads * 91)/bp) %>% # Calculate coverage
mutate(n_alleles = map_dbl(allele, function(x) sum(!is.na(x)))) %>% # Calculate n_alleles
filter(grepl("^[ABC]|D.[AB]1", locus) & grepl("-(AC|BL)", sample) & genotyper != "hlaminer")
Reads plots
gg_coverage(subsample_reads_combined_df, x_var = "reads", y_var = "accuracy")
`geom_smooth()` using formula 'y ~ x'

plt_read_accuracy_all <- gg_coverage(subsample_reads_combined_df, x_var = "reads", y_var = "accuracy")
plt_read_accuracy_abc <- gg_coverage(subsample_reads_combined_df %>% filter(grepl("^[ABC]", locus)), x_var = "reads", y_var = "accuracy")
gg_coverage(subsample_reads_combined_df, x_var = "reads", y_var = "success")
`geom_smooth()` using formula 'y ~ x'

plt_read_success_all <- gg_coverage(subsample_reads_combined_df, x_var = "reads", y_var = "success")
plt_read_success_abc <- gg_coverage(subsample_reads_combined_df %>% filter(grepl("^[ABC]", locus)), x_var = "reads", y_var = "success")
gg_coverage(subsample_reads_combined_df, x_var = "reads", y_var = "n_alleles", facet_genotyper = T)

plt_read_allele_all <- gg_coverage(subsample_reads_combined_df, x_var = "reads", y_var = "n_alleles", facet_genotyper = T)
plt_read_allele_abc <- gg_coverage(subsample_reads_combined_df %>% filter(grepl("^[ABC]", locus)), x_var = "reads", y_var = "n_alleles", facet_genotyper = T)
- Default arcasHLA cut off 75 reads (log10 = 1.8)
subsample_reads_combined_df %>%
filter(field == "field_2") %>%
mutate(n_alleles = factor(n_alleles, levels = 0:2)) %>%
ggplot(aes(y = n_alleles, x = log10(coverage)))+
# geom_violin(scale = "count", alpha = 0.5, )+
geom_jitter(size = 0.2, width = 0, height =0.2, alpha = 0.2)+
# geom_boxplot(width=0.1)+
# ggbeeswarm::geom_beeswarm(size = 0.1, alpha = 0.1)+
# coord_flip()+
facet_grid(genotyper ~ locus, scales = "free")+
theme_bw()

Subsample CELLS
# Import predicted genotypes
subsample_cells_path <- "/labs/khatrilab/solomonb/covid/isb/subsample_cells"
subsample_cells_samples <- tibble(sample = list.files(sprintf("%s/arcasHLA", subsample_cells_path))) %>%
filter(grepl("^INCOV", sample)) %>%
separate(sample, into = c("sample"), sep = "\\.", extra = "drop") %>%
distinct() %>%
pull(sample)
subsample_cells_df <- format_hla_table(combine_HLA_import(path = subsample_cells_path, samples = subsample_cells_samples))
subsample_cells_df <- subsample_cells_df %>%
filter(grepl("^[ABC]|D.[AB]1", locus) & grepl("-(AC|BL)_", sample))
subsample_cells_df
# Expand invitro genotypes across read subsample names
invitro_df <- invitro_import()
Rows: 1557 Columns: 9
── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (8): Sample ID, Locus, Allele 1, Allele 2, Comments, Diploid Ambiguities, Allele 1 Ambiguities, Allele 2 Ambiguities
dbl (1): index
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
invitro_cells_df <- subsample_cells_df %>%
select(sample) %>%
distinct() %>%
separate(sample, into = c("sample", "subsample"), sep = "_") %>%
left_join(invitro_df, by = "sample") %>%
unite(sample, sample, subsample, sep = "_") %>%
format_hla_table() %>%
drop_na()
invitro_cells_df
# Import read statistics
subsample_cells_arcas_log_dir <- sprintf("%s/arcasHLA", subsample_cells_path)
subsample_cells_alignment_stats_df <- hla_mapping_stats_import(subsample_cells_samples, subsample_cells_arcas_log_dir)
# Import cell counts for each subsample
subsample_cell_counts_df <- tibble(line = system("wc -l /labs/khatrilab/solomonb/covid/isb/subsample_cells/barcodes/INCOV*", intern = T)) %>%
separate(line, into = c("n_cells", "file"), sep = " /") %>%
drop_na() %>%
mutate(sample = gsub("\\..*","",basename(file))) %>%
mutate(n_cells = as.numeric(n_cells)) %>%
select(-file) %>%
# separate(sample, into = c("sample", "subset"), sep = "_") %>%
bind_rows(cell_counts_df)
Warning: Expected 2 pieces. Missing pieces filled with `NA` in 1 rows [883].
subsample_cell_counts_df
Calculate accuracy
# Calculate accuracy
subsample_cells_accuracy_df <- compare_hla(
hla_df = bind_rows(
subsample_cells_df,
invitro_cells_df
),
reference = "invitro",
method = "accuracy"
)
# saveRDS(subsample_cells_accuracy_df, "isb_subsample_cells_accuracy.RDS")
# Calculate success
subsample_cells_success_df <- compare_hla(
hla_df = bind_rows(
subsample_cells_df,
invitro_cells_df
),
reference = "invitro",
method = "success"
)
# saveRDS(subsample_cells_success_df, "isb_subsample_cells_success.RDS")
# Combine various data
subsample_cells_combined_df <- subsample_cells_accuracy_df %>%
left_join(
subsample_cells_success_df %>% select(sample:field, genotyper, success = accuracy),
by = c("sample", "locus", "field", "genotyper")
)%>%
left_join(subsample_cells_alignment_stats_df, by = c("sample", "locus")) %>%
left_join(genome_region_reference, by = "locus") %>%
left_join(subsample_cell_counts_df, by = "sample") %>%
bind_rows(accuracy_df) %>%
mutate_at(vars(c(reads, bp)), as.numeric) %>%
mutate(coverage = (reads * 91)/bp) %>%
mutate(n_alleles = map_dbl(allele, function(x) sum(!is.na(x)))) %>%
filter(grepl("^[ABC]|D.[AB]1", locus) & grepl("-(AC|BL)", sample) & genotyper != "hlaminer")
Coverage plots
gg_coverage(subsample_cells_combined_df, x_var = "coverage", y_var = "accuracy")
`geom_smooth()` using formula 'y ~ x'

gg_coverage(subsample_cells_combined_df, x_var = "coverage", y_var = "success")
`geom_smooth()` using formula 'y ~ x'

gg_coverage(subsample_cells_combined_df, x_var = "coverage", y_var = "n_alleles", facet_genotyper = T)

Cell number plots
gg_coverage(subsample_cells_combined_df, x_var = "n_cells", y_var = "accuracy")
`geom_smooth()` using formula 'y ~ x'

plt_cell_accuracy_all <- gg_coverage(subsample_cells_combined_df, x_var = "n_cells", y_var = "accuracy")
plt_cell_accuracy_abc <- gg_coverage(subsample_cells_combined_df %>% filter(grepl("^[ABC]", locus)), x_var = "n_cells", y_var = "accuracy")
gg_coverage(subsample_cells_combined_df, x_var = "n_cells", y_var = "success")
`geom_smooth()` using formula 'y ~ x'

plt_cell_success_all <- gg_coverage(subsample_cells_combined_df, x_var = "n_cells", y_var = "success")
plt_cell_success_abc <- gg_coverage(subsample_cells_combined_df %>% filter(grepl("^[ABC]", locus)), x_var = "n_cells", y_var = "success")
gg_coverage(subsample_cells_combined_df, x_var = "n_cells", y_var = "n_alleles", facet_genotyper = T)

plt_cell_allele_all <- gg_coverage(subsample_cells_combined_df, x_var = "n_cells", y_var = "n_alleles", facet_genotyper = T)
plt_cell_allele_abc <- gg_coverage(subsample_cells_combined_df %>% filter(grepl("^[ABC]", locus)), x_var = "n_cells", y_var = "n_alleles", facet_genotyper = T)
# subsample_cells_combined_df %>%
# mutate(reads = reads/n_cells) %>%
# filter(reads < 100) %>%
# gg_coverage(x_var = "reads", y_var = "accuracy", x_log = F)
Combined plots
no_leg <- list(theme(legend.position = "none"))
legend <- cowplot::get_legend(plt_read_accuracy_abc)
`geom_smooth()` using formula 'y ~ x'
plot_grid(
plot_grid(
plt_read_accuracy_abc + no_leg,
plt_read_success_abc + no_leg,
plt_read_allele_abc,
ncol = 1,
align = "v",
axis = "lr",
rel_heights = c(1,1,1.2),
labels = LETTERS[1:3]
),
plot_grid(
plt_cell_accuracy_abc + no_leg,
plt_cell_success_abc + no_leg,
plt_cell_allele_abc,
ncol = 1,
align = "v",
axis = "lr",
rel_heights = c(1,1,1.2),
labels = LETTERS[4:6]
),
plot_grid(
legend,
legend,
NA,
ncol = 1
),
nrow = 1,
rel_widths = c(1,1,0.25)
)
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'

no_leg <- list(theme(legend.position = "none"))
legend <- cowplot::get_legend(plt_read_accuracy_all)
`geom_smooth()` using formula 'y ~ x'
plot_grid(
plot_grid(
plt_read_accuracy_all + no_leg,
plt_read_success_all + no_leg,
plt_read_allele_all,
ncol = 1,
align = "v",
axis = "lr",
rel_heights = c(1,1,1.2),
labels = LETTERS[1:3]
),
plot_grid(
plt_cell_accuracy_all + no_leg,
plt_cell_success_all + no_leg,
plt_cell_allele_all,
ncol = 1,
align = "v",
axis = "lr",
rel_heights = c(1,1,1.2),
labels = LETTERS[4:6]
),
plot_grid(
legend,
legend,
NA,
ncol = 1
),
nrow = 1,
rel_widths = c(1,1,0.25)
)
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'

Slope stats
get_lm_stats <- function(df, x_var = "coverage", y_var = "accuracy", field_var = "field_2", x_log = T){
# Input checks
arg_col <- makeAssertCollection()
assertChoice(y_var, c("accuracy", "success", "n_alleles"), add = arg_col)
assertChoice(x_var, c("reads", "coverage", "n_cells"), add = arg_col)
assertChoice(field_var, c("field_1", "field_2", "field_3"), add = arg_col)
assertLogical(x_log, add = arg_col)
if (arg_col$isEmpty()==F) {map(arg_col$getMessages(),print);reportAssertions(arg_col)}
# browser()
df <- df %>%
filter(field == field_var) %>%
remove_invalid_combinations()
if (x_log ==T){df <- df %>% mutate_at(x_var, log10)}
df %>%
filter_at(x_var, function(x) !is.na(x) & !is.infinite(x)) %>%
group_by(locus, field, genotyper) %>%
nest() %>%
mutate(data = map(data, function(x){
summary(lm(!!sym(y_var) ~ !!sym(x_var), data = x)) %>% broom::tidy() %>% filter(term == x_var)
})) %>% unnest_wider(data) %>%
mutate(est_min = round(estimate - 2*std.error, 2),
est_max = round(estimate + 2*std.error, 2))
}
model_stats <- get_lm_stats(subsample_cells_combined_df, x_var = "reads", y_var = "accuracy", x_log = T)
model_stats
model_stats <- bind_rows(
get_lm_stats(subsample_reads_combined_df, x_var = "reads", y_var = "accuracy", x_log = T) %>% mutate(x_var = "reads", y_var = "accuracy"),
get_lm_stats(subsample_reads_combined_df, x_var = "reads", y_var = "success", x_log = T) %>% mutate(x_var = "reads", y_var = "success"),
get_lm_stats(subsample_cells_combined_df, x_var = "n_cells", y_var = "accuracy", x_log = T) %>% mutate(x_var = "cells", y_var = "accuracy"),
get_lm_stats(subsample_cells_combined_df, x_var = "n_cells", y_var = "success", x_log = T) %>% mutate(x_var = "cells", y_var = "success")
) %>%
# filter(grepl("^[ABC]", locus)) %>%
ungroup() %>%
filter(field == "field_2")
Table
col_vars <- c("x_var", "locus")
row_vars <- c("y_var", "genotyper")
flex_df <- model_stats %>%
# filter(grepl("^[ABC]", locus)) %>%
ungroup() %>%
filter(field == "field_2") %>%
mutate(CI = sprintf("(%s) - (%s)", est_min, est_max)) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
select(genotyper, locus, CI, x_var, y_var) %>%
pivot_wider(names_from = col_vars, values_from = "CI", names_sep = "-")
Note: Using an external vector in selections is ambiguous.
ℹ Use `all_of(col_vars)` instead of `col_vars` to silence this message.
ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
df_key <- tibble(col_keys = names(flex_df)) %>%
filter(!(col_keys %in% c(col_vars, row_vars))) %>%
separate(col_keys, into = col_vars, sep = "-", remove = F) %>%
mutate_at(vars(contains("genotyper")), reformat_hla_genotyper) %>%
arrange_at(col_vars) %>%
mutate_all(as.character) %>%
mutate_at(col_vars[!(col_vars %in% "locus")], str_to_sentence)
flex_df %>%
select(row_vars, everything()) %>%
mutate_at(row_vars[!(row_vars %in% "genotyper")], str_to_sentence) %>%
# select(locus, df_key$col_keys) %>%
flextable() %>%
colformat_char(na_str = "---") %>%
merge_v(j=1:2) %>%
set_header_df(mapping = df_key, key = "col_keys") %>%
merge_h(part = "header") %>%
theme_vanilla() %>%
# vline(j=vlines_sequence, border = fp_border_default()) %>%
fix_border_issues() %>%
autofit() %>%
fontsize(size = 8, part = "all") %>%
print(preview = "pptx")
Note: Using an external vector in selections is ambiguous.
ℹ Use `all_of(row_vars)` instead of `row_vars` to silence this message.
ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
df <- df %>%
mutate(field = reformat_hla_field(field)) %>%
mutate_at(vars(contains("genotyper")), reformat_hla_genotyper) %>%
mutate(cell_value = ifelse(!is.na(se),
sprintf("%s %s %s", round(mean_accuracy,2),"\u00B1",round(se,2)),
sprintf("%s", round(mean_accuracy,2)))) %>%
mutate(cell_value = ifelse(grepl("NA", cell_value), NA, cell_value)) %>%
select(-sd,-se, -mean_accuracy) %>%
pivot_wider(names_from = nesting_vars, values_from = "cell_value", names_sep = "-")
Error: Problem with `mutate()` column `field`.
ℹ `field = reformat_hla_field(field)`.
x object 'field' not found
Run `rlang::last_error()` to see where the error occurred.
Scratch work
subsample_cells_combined_df %>%
filter(field == "field_2") %>%
mutate(n_alleles = factor(n_alleles, levels = 0:2)) %>%
ggplot(aes(x = n_alleles, y = log10(n_cells)))+
geom_violin(scale = "width")+
geom_jitter(size = 0.2, height = 0, width =0.05, alpha = 0.2)+
# geom_boxplot(width=0.1)+
# ggbeeswarm::geom_beeswarm(size = 0.1, alpha = 0.1)+
coord_flip()+
facet_grid(genotyper ~ locus, scales = "free")+
theme_bw()
Coverage stats
subsample_cells_combined_df %>%
ggplot(aes(x = n_cells, y = coverage, color = genotyper)) +
geom_point() +
facet_wrap(genotyper ~ locus, scales = "free", nrow = 3) +
theme_bw() +
theme(strip.text = element_blank(),
axis.text.x = element_text(angle = 45, hjust = 1))+
scale_color_brewer(palette = "Dark2")
subsample_cells_combined_df %>%
select(-genotyper) %>% distinct() %>%
mutate(cov_per_cell = coverage/n_cells) %>%
ggplot(aes(x = log10(n_cells), y = cov_per_cell)) +
geom_point(color = "black", alpha = 0.1) +
stat_smooth(method = "lm")+
# stat_smooth()+
facet_wrap( ~ locus, scales = "free", nrow = 1) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))+
scale_color_brewer(palette = "Dark2")
subsample_cells_combined_df %>%
select(-genotyper) %>% distinct() %>%
filter(!is.na(n_cells)) %>%
mutate(cov_per_cell = coverage/n_cells) %>%
mutate(n_cells = cut(n_cells, seq(0,10000,by=2500), right = F)) %>%
ggplot(aes(x = n_cells, y = cov_per_cell)) +
stat_summary(fun = function(x) mean(x,na.rm=T), geom = "bar") +
# geom_point(color = "black", alpha = 0.1) +
# stat_smooth(method = "lm")+
# stat_smooth()+
facet_wrap( ~ locus, scales = "free", nrow = 1) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))+
scale_color_brewer(palette = "Dark2")
hist(cut(1:100, seq(1,100,10)))
subsample_cells_combined_df %>%
ungroup() %>%
count(genotyper, locus, field)
subsample_reads_combined_df %>%
ungroup() %>%
count(genotyper, locus, field)
LS0tCnRpdGxlOiAiMykgQ292ZXJhZ2UgQW5hbHlzaXMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCgojIFN0YXJ0dXAgCgpgYGB7ciwgbWVzc2FnZSA9IEZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoZ2dwbWlzYykKCnNvdXJjZSgiZGF0YV9pbXBvcnRfZnVuY3Rpb25zLlIiKQpzb3VyY2UoImNhbGN1bGF0aW9uX2Z1bmN0aW9ucy5SIikKc291cmNlKCJmaWd1cmVfZm9ybWF0X2Z1bmN0aW9ucy5SIikKYWxsX2hsYV9leHBhbmRlZCA8LSByZWFkUkRTKCJhbGxfaGxhX2V4cGFuZGVkLlJEUyIpCmlzYl9wYXRoIDwtICIvbGFicy9raGF0cmlsYWIvc29sb21vbmIvY292aWQvaXNiIgppc2Jfc2FtcGxlcyA8LSByZWFkX3RzdigiL2xhYnMva2hhdHJpbGFiL3NvbG9tb25iL2NvdmlkL2lzYi9sb2dzLzIxMDIxN18yMzI3MjUvcGFyYWxsZWwubG9nIikgJT4lIAogIHNlcGFyYXRlKENvbW1hbmQsIGludG8gPSBjKE5BLCAic2FtcGxlIiksIHNlcCA9ICIgIikgJT4lIAogIHB1bGwoc2FtcGxlKSAlPiUgdW5pcXVlKCkKYGBgCgojIyMgR2V0IHJlZmVyZW5jZSBhbGxlbGVzCgotIEdDaDM4IHJlZmVyZW5jZSBhbGxlbGVzIChwZXIgaHR0cHM6Ly93d3cuZWJpLmFjLnVrL2lwZC9pbWd0L2hsYS9oZWxwL2dlbm9taWNzLmh0bWwpCi0gVG8gYmUgdXNlZCB0byBjYWxjdWxhdGUgY292ZXJhZ2UKCmBgYHtyLCBtZXNzYWdlID0gRn0KcmVmZXJlbmNlX2FsbGVsZXMgPC0gcmVhZF90c3YoIkdDaDM4X3JlZmVyZW5jZV9hbGxlbGVzLnR4dCIsIGNvbF9uYW1lcyA9IEYpICU+JSBwdWxsKDEpCmdlbm9tZV9yZWdpb25fcmVmZXJlbmNlIDwtIGdldF9hbGxlbGVfbGVuZ3RoKHJlZmVyZW5jZV9hbGxlbGVzKQpgYGAKCiMjIyBHZXQgYXJjYXNITEEgYWxpZ25tZW50IHN0YXRzCgpgYGB7cn0KYXJjYXNfbG9nX2RpciA8LSBzcHJpbnRmKCIlcy9hcmNhc0hMQSIsIGlzYl9wYXRoKQphbGlnbm1lbnRfc3RhdHNfZGYgPC0gaGxhX21hcHBpbmdfc3RhdHNfaW1wb3J0KGlzYl9zYW1wbGVzLCBhcmNhc19sb2dfZGlyKQpgYGAKCiMjIyBJbXBvcnQgY2VsbCBjb3VudHMKCmBgYHtyfQpjZWxsX2NvdW50c19kZiA8LSByZWFkUkRTKCJpc2Jfc2VxdWVuY2VkX2NlbGxfY291bnQuUkRTIikKYGBgCgojIyMgQXNzZW1ibGUgYWNjdXJhY3kgREYKCmBgYHtyfQpzdWNjZXNzX2RmIDwtIHJlYWRSRFMoImlzYl9zdWNjZXNzLlJEUyIpCmFjY3VyYWN5X2RmIDwtIHJlYWRSRFMoImlzYl9hY2N1cmFjeV9kcmIzNDVfZmlsdGVyZWQuUkRTIikKYWNjdXJhY3lfZGYgPC0gYWNjdXJhY3lfZGYgJT4lIAogIGxlZnRfam9pbigKICAgIHN1Y2Nlc3NfZGYgJT4lIHNlbGVjdChzYW1wbGU6ZmllbGQsIGdlbm90eXBlciwgc3VjY2VzcyA9IGFjY3VyYWN5KSwKICAgIGJ5ID0gYygic2FtcGxlIiwgImxvY3VzIiwgImZpZWxkIiwgImdlbm90eXBlciIpCiAgKSU+JSAKICBsZWZ0X2pvaW4oYWxpZ25tZW50X3N0YXRzX2RmLCBieSA9IGMoInNhbXBsZSIsICJsb2N1cyIpKSAlPiUgCiAgbGVmdF9qb2luKGdlbm9tZV9yZWdpb25fcmVmZXJlbmNlLCBieSA9ICJsb2N1cyIpICU+JQogIGxlZnRfam9pbihjZWxsX2NvdW50c19kZiwgYnkgPSAic2FtcGxlIikgJT4lCiAgbXV0YXRlX2F0KHZhcnMoYyhyZWFkcywgYnApKSwgYXMubnVtZXJpYykgJT4lIAogIG11dGF0ZShjb3ZlcmFnZSA9IChyZWFkcyAqIDkxKS9icCkgJT4lIAogIG11dGF0ZShuX2FsbGVsZXMgPSBtYXBfZGJsKGFsbGVsZSwgZnVuY3Rpb24oeCkgc3VtKCFpcy5uYSh4KSkpKSAlPiUgCiAgZmlsdGVyKGdyZXBsKCJeW0FCQ118RC5bQUJdMSIsIGxvY3VzKSAmIGdyZXBsKCItKEFDfEJMKSQiLCBzYW1wbGUpICYgZ2Vub3R5cGVyICE9ICJobGFtaW5lciIpIApgYGAKCgojIyMgQ292ZXJhZ2UgYmFzZWQgcGxvdHMKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Mi41LCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9CmdnX2NvdmVyYWdlKGFjY3VyYWN5X2RmLCB4X3ZhciA9ICJjb3ZlcmFnZSIsIHlfdmFyID0gImFjY3VyYWN5IikgCmBgYApgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTIuNSwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQpnZ19jb3ZlcmFnZShhY2N1cmFjeV9kZiwgeF92YXIgPSAiY292ZXJhZ2UiLCB5X3ZhciA9ICJzdWNjZXNzIikKYGBgCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Mywgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQpnZ19jb3ZlcmFnZShhY2N1cmFjeV9kZiwgeF92YXIgPSAiY292ZXJhZ2UiLCB5X3ZhciA9ICJuX2FsbGVsZXMiLCBmYWNldF9nZW5vdHlwZXIgPSBUKQpgYGAKCiMjIyBDZWxsIG51bWJlciBiYXNlZCBwbG90cwoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0yLjUsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0KZ2dfY292ZXJhZ2UoYWNjdXJhY3lfZGYsIHhfdmFyID0gIm5fY2VsbHMiLCB5X3ZhciA9ICJhY2N1cmFjeSIpIApgYGAKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0yLjUsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0KZ2dfY292ZXJhZ2UoYWNjdXJhY3lfZGYsIHhfdmFyID0gIm5fY2VsbHMiLCB5X3ZhciA9ICJzdWNjZXNzIikKYGBgCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Mywgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQpnZ19jb3ZlcmFnZShhY2N1cmFjeV9kZiwgeF92YXIgPSAibl9jZWxscyIsIHlfdmFyID0gIm5fYWxsZWxlcyIsIGZhY2V0X2dlbm90eXBlciA9IFQpCmBgYAoKCiMgU3Vic2FtcGxlIFJFQURTCgojIyMgSW1wb3J0IHJlYWQgc3Vic2FtcGxlIGRhdGEKCmBgYHtyfQojIEltcG9ydCBwcmVkaWN0ZWQgZ2Vub3R5cGVzCnN1YnNhbXBsZV9yZWFkc19wYXRoIDwtICIvbGFicy9raGF0cmlsYWIvc29sb21vbmIvY292aWQvaXNiL3N1YnNhbXBsZSIKc3Vic2FtcGxlX3JlYWRzX3NhbXBsZXMgPC0gdGliYmxlKHNhbXBsZSA9IGxpc3QuZmlsZXMoc3ByaW50ZigiJXMvYXJjYXNITEEiLCBzdWJzYW1wbGVfcmVhZHNfcGF0aCkpKSAlPiUgCiAgZmlsdGVyKGdyZXBsKCJeSU5DT1YiLCBzYW1wbGUpKSAlPiUgCiAgc2VwYXJhdGUoc2FtcGxlLCBpbnRvID0gYygic2FtcGxlIiksIHNlcCA9ICJcXC4iLCBleHRyYSA9ICJkcm9wIikgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIHB1bGwoc2FtcGxlKQpzdWJzYW1wbGVfcmVhZHNfZGYgPC0gZm9ybWF0X2hsYV90YWJsZShjb21iaW5lX0hMQV9pbXBvcnQocGF0aCA9IHN1YnNhbXBsZV9yZWFkc19wYXRoLCBzYW1wbGVzID0gc3Vic2FtcGxlX3JlYWRzX3NhbXBsZXMpKQpzdWJzYW1wbGVfcmVhZHNfZGYgPC0gc3Vic2FtcGxlX3JlYWRzX2RmICU+JSAKICBmaWx0ZXIoZ3JlcGwoIl5bQUJDXXxELltBQl0xIiwgbG9jdXMpICYgZ3JlcGwoIi0oQUN8QkwpXyIsIHNhbXBsZSkpCnN1YnNhbXBsZV9yZWFkc19kZgpgYGAKCmBgYHtyLCBtZXNzYWdlID0gRn0KIyBFeHBhbmQgaW52aXRybyBnZW5vdHlwZXMgYWNyb3NzIHJlYWQgc3Vic2FtcGxlIG5hbWVzCmludml0cm9fZGYgPC0gaW52aXRyb19pbXBvcnQoKQppbnZpdHJvX3JlYWRzX2RmIDwtIHN1YnNhbXBsZV9yZWFkc19kZiAlPiUgCiAgc2VsZWN0KHNhbXBsZSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIHNlcGFyYXRlKHNhbXBsZSwgaW50byA9IGMoInNhbXBsZSIsICJzdWJzYW1wbGUiKSwgc2VwID0gIl8iKSAlPiUgCiAgbGVmdF9qb2luKGludml0cm9fZGYsIGJ5ID0gInNhbXBsZSIpICU+JSAKICB1bml0ZShzYW1wbGUsIHNhbXBsZSwgc3Vic2FtcGxlLCBzZXAgPSAiXyIpICU+JSAKICBmb3JtYXRfaGxhX3RhYmxlKCkgJT4lIAogIGRyb3BfbmEoKQppbnZpdHJvX3JlYWRzX2RmCmBgYAoKYGBge3J9CiMgSW1wb3J0IHJlYWQgc3RhdGlzdGljcwpzdWJzYW1wbGVfcmVhZHNfYXJjYXNfbG9nX2RpciA8LSBzcHJpbnRmKCIlcy9hcmNhc0hMQSIsIHN1YnNhbXBsZV9yZWFkc19wYXRoKQpzdWJzYW1wbGVfcmVhZHNfYWxpZ25tZW50X3N0YXRzX2RmIDwtIGhsYV9tYXBwaW5nX3N0YXRzX2ltcG9ydChzdWJzYW1wbGVfcmVhZHNfc2FtcGxlcywgc3Vic2FtcGxlX3JlYWRzX2FyY2FzX2xvZ19kaXIpCmBgYAoKIyMjIENhbGN1bGF0ZSBhY2N1cmFjeQoKYGBge3J9CiMgQ2FsY3VsYXRlIGFjY3VyYWN5CnN1YnNhbXBsZV9yZWFkc19hY2N1cmFjeV9kZiA8LSBjb21wYXJlX2hsYSgKICBobGFfZGYgPSBiaW5kX3Jvd3MoCiAgICBzdWJzYW1wbGVfcmVhZHNfZGYsCiAgICBpbnZpdHJvX3JlYWRzX2RmCiAgKSwKICByZWZlcmVuY2UgPSAiaW52aXRybyIsIAogIG1ldGhvZCA9ICJhY2N1cmFjeSIKKQojIHNhdmVSRFMoc3Vic2FtcGxlX3JlYWRzX2FjY3VyYWN5X2RmLCAiaXNiX3N1YnNhbXBsZV9yZWFkc19hY2N1cmFjeS5SRFMiKQpgYGAKCgpgYGB7cn0KIyBDYWxjdWxhdGUgc3VjY2VzcwpzdWJzYW1wbGVfcmVhZHNfc3VjY2Vzc19kZiA8LSBjb21wYXJlX2hsYSgKICBobGFfZGYgPSBiaW5kX3Jvd3MoCiAgICBzdWJzYW1wbGVfcmVhZHNfZGYsCiAgICBpbnZpdHJvX3JlYWRzX2RmCiAgKSwKICByZWZlcmVuY2UgPSAiaW52aXRybyIsIAogIG1ldGhvZCA9ICJzdWNjZXNzIgopCiMgc2F2ZVJEUyhzdWJzYW1wbGVfcmVhZHNfc3VjY2Vzc19kZiwgImlzYl9zdWJzYW1wbGVfcmVhZHNfc3VjY2Vzcy5SRFMiKQpgYGAKCmBgYHtyfQojIENvbWJpbmUgdmFyaW91cyBkYXRhCnN1YnNhbXBsZV9yZWFkc19jb21iaW5lZF9kZiA8LSBzdWJzYW1wbGVfcmVhZHNfYWNjdXJhY3lfZGYgJT4lIAogIGxlZnRfam9pbigKICAgIHN1YnNhbXBsZV9yZWFkc19zdWNjZXNzX2RmICU+JSBzZWxlY3Qoc2FtcGxlOmZpZWxkLCBnZW5vdHlwZXIsIHN1Y2Nlc3MgPSBhY2N1cmFjeSksCiAgICBieSA9IGMoInNhbXBsZSIsICJsb2N1cyIsICJmaWVsZCIsICJnZW5vdHlwZXIiKQogICklPiUgCiAgbGVmdF9qb2luKHN1YnNhbXBsZV9yZWFkc19hbGlnbm1lbnRfc3RhdHNfZGYsIGJ5ID0gYygic2FtcGxlIiwgImxvY3VzIikpICU+JSAKICBsZWZ0X2pvaW4oZ2Vub21lX3JlZ2lvbl9yZWZlcmVuY2UsIGJ5ID0gImxvY3VzIikgJT4lCiAgYmluZF9yb3dzKGFjY3VyYWN5X2RmICU+JSBzZWxlY3QoLW5fY2VsbHMpKSAlPiUgIyBObyBjZWxsIG51bWJlcnMgZm9yIHJlYWQgc3Vic2FtcGxlcwogIG11dGF0ZV9hdCh2YXJzKGMocmVhZHMsIGJwKSksIGFzLm51bWVyaWMpICU+JSAKICBtdXRhdGUoY292ZXJhZ2UgPSAocmVhZHMgKiA5MSkvYnApICU+JSAgIyBDYWxjdWxhdGUgY292ZXJhZ2UKICBtdXRhdGUobl9hbGxlbGVzID0gbWFwX2RibChhbGxlbGUsIGZ1bmN0aW9uKHgpIHN1bSghaXMubmEoeCkpKSkgJT4lICAjIENhbGN1bGF0ZSBuX2FsbGVsZXMKICBmaWx0ZXIoZ3JlcGwoIl5bQUJDXXxELltBQl0xIiwgbG9jdXMpICYgZ3JlcGwoIi0oQUN8QkwpIiwgc2FtcGxlKSAmIGdlbm90eXBlciAhPSAiaGxhbWluZXIiKSAKYGBgCgojIyMgUmVhZHMgcGxvdHMKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0yLjUsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0KZ2dfY292ZXJhZ2Uoc3Vic2FtcGxlX3JlYWRzX2NvbWJpbmVkX2RmLCB4X3ZhciA9ICJyZWFkcyIsIHlfdmFyID0gImFjY3VyYWN5IikgCnBsdF9yZWFkX2FjY3VyYWN5X2FsbCA8LSBnZ19jb3ZlcmFnZShzdWJzYW1wbGVfcmVhZHNfY29tYmluZWRfZGYsIHhfdmFyID0gInJlYWRzIiwgeV92YXIgPSAiYWNjdXJhY3kiKSAKcGx0X3JlYWRfYWNjdXJhY3lfYWJjIDwtIGdnX2NvdmVyYWdlKHN1YnNhbXBsZV9yZWFkc19jb21iaW5lZF9kZiAlPiUgZmlsdGVyKGdyZXBsKCJeW0FCQ10iLCBsb2N1cykpLCB4X3ZhciA9ICJyZWFkcyIsIHlfdmFyID0gImFjY3VyYWN5IikgCmBgYApgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTIuNSwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQpnZ19jb3ZlcmFnZShzdWJzYW1wbGVfcmVhZHNfY29tYmluZWRfZGYsIHhfdmFyID0gInJlYWRzIiwgeV92YXIgPSAic3VjY2VzcyIpCnBsdF9yZWFkX3N1Y2Nlc3NfYWxsIDwtIGdnX2NvdmVyYWdlKHN1YnNhbXBsZV9yZWFkc19jb21iaW5lZF9kZiwgeF92YXIgPSAicmVhZHMiLCB5X3ZhciA9ICJzdWNjZXNzIikKcGx0X3JlYWRfc3VjY2Vzc19hYmMgPC0gZ2dfY292ZXJhZ2Uoc3Vic2FtcGxlX3JlYWRzX2NvbWJpbmVkX2RmICU+JSBmaWx0ZXIoZ3JlcGwoIl5bQUJDXSIsIGxvY3VzKSksIHhfdmFyID0gInJlYWRzIiwgeV92YXIgPSAic3VjY2VzcyIpIApgYGAKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0zLCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9CmdnX2NvdmVyYWdlKHN1YnNhbXBsZV9yZWFkc19jb21iaW5lZF9kZiwgeF92YXIgPSAicmVhZHMiLCB5X3ZhciA9ICJuX2FsbGVsZXMiLCBmYWNldF9nZW5vdHlwZXIgPSBUKQpwbHRfcmVhZF9hbGxlbGVfYWxsIDwtIGdnX2NvdmVyYWdlKHN1YnNhbXBsZV9yZWFkc19jb21iaW5lZF9kZiwgeF92YXIgPSAicmVhZHMiLCB5X3ZhciA9ICJuX2FsbGVsZXMiLCBmYWNldF9nZW5vdHlwZXIgPSBUKQpwbHRfcmVhZF9hbGxlbGVfYWJjIDwtIGdnX2NvdmVyYWdlKHN1YnNhbXBsZV9yZWFkc19jb21iaW5lZF9kZiAlPiUgZmlsdGVyKGdyZXBsKCJeW0FCQ10iLCBsb2N1cykpLCB4X3ZhciA9ICJyZWFkcyIsIHlfdmFyID0gIm5fYWxsZWxlcyIsIGZhY2V0X2dlbm90eXBlciA9IFQpCmBgYAotIERlZmF1bHQgYXJjYXNITEEgY3V0IG9mZiA3NSByZWFkcyAobG9nMTAgPSAxLjgpCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTMsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0Kc3Vic2FtcGxlX3JlYWRzX2NvbWJpbmVkX2RmICU+JSAKICBmaWx0ZXIoZmllbGQgPT0gImZpZWxkXzIiKSAlPiUgCiAgbXV0YXRlKG5fYWxsZWxlcyA9IGZhY3RvcihuX2FsbGVsZXMsIGxldmVscyA9IDA6MikpICU+JSAKICBnZ3Bsb3QoYWVzKHkgPSBuX2FsbGVsZXMsIHggPSBsb2cxMChjb3ZlcmFnZSkpKSsKICAjIGdlb21fdmlvbGluKHNjYWxlID0gImNvdW50IiwgYWxwaGEgPSAwLjUsICkrCiAgZ2VvbV9qaXR0ZXIoc2l6ZSA9IDAuMiwgd2lkdGggPSAwLCBoZWlnaHQgPTAuMiwgYWxwaGEgPSAwLjIpKwogICMgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMSkrCiAgIyBnZ2JlZXN3YXJtOjpnZW9tX2JlZXN3YXJtKHNpemUgPSAwLjEsIGFscGhhID0gMC4xKSsKICAjIGNvb3JkX2ZsaXAoKSsKICBmYWNldF9ncmlkKGdlbm90eXBlciB+IGxvY3VzLCBzY2FsZXMgPSAiZnJlZSIpKwogIHRoZW1lX2J3KCkKYGBgCgojIFN1YnNhbXBsZSBDRUxMUwoKYGBge3J9CiMgSW1wb3J0IHByZWRpY3RlZCBnZW5vdHlwZXMKc3Vic2FtcGxlX2NlbGxzX3BhdGggPC0gIi9sYWJzL2toYXRyaWxhYi9zb2xvbW9uYi9jb3ZpZC9pc2Ivc3Vic2FtcGxlX2NlbGxzIgpzdWJzYW1wbGVfY2VsbHNfc2FtcGxlcyA8LSB0aWJibGUoc2FtcGxlID0gbGlzdC5maWxlcyhzcHJpbnRmKCIlcy9hcmNhc0hMQSIsIHN1YnNhbXBsZV9jZWxsc19wYXRoKSkpICU+JSAKICBmaWx0ZXIoZ3JlcGwoIl5JTkNPViIsIHNhbXBsZSkpICU+JSAKICBzZXBhcmF0ZShzYW1wbGUsIGludG8gPSBjKCJzYW1wbGUiKSwgc2VwID0gIlxcLiIsIGV4dHJhID0gImRyb3AiKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgcHVsbChzYW1wbGUpCnN1YnNhbXBsZV9jZWxsc19kZiA8LSBmb3JtYXRfaGxhX3RhYmxlKGNvbWJpbmVfSExBX2ltcG9ydChwYXRoID0gc3Vic2FtcGxlX2NlbGxzX3BhdGgsIHNhbXBsZXMgPSBzdWJzYW1wbGVfY2VsbHNfc2FtcGxlcykpCnN1YnNhbXBsZV9jZWxsc19kZiA8LSBzdWJzYW1wbGVfY2VsbHNfZGYgJT4lIAogIGZpbHRlcihncmVwbCgiXltBQkNdfEQuW0FCXTEiLCBsb2N1cykgJiBncmVwbCgiLShBQ3xCTClfIiwgc2FtcGxlKSkKc3Vic2FtcGxlX2NlbGxzX2RmCmBgYAoKCmBgYHtyLCBtZXNzYWdlID0gRn0KIyBFeHBhbmQgaW52aXRybyBnZW5vdHlwZXMgYWNyb3NzIHJlYWQgc3Vic2FtcGxlIG5hbWVzCmludml0cm9fZGYgPC0gaW52aXRyb19pbXBvcnQoKQppbnZpdHJvX2NlbGxzX2RmIDwtIHN1YnNhbXBsZV9jZWxsc19kZiAlPiUgCiAgc2VsZWN0KHNhbXBsZSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIHNlcGFyYXRlKHNhbXBsZSwgaW50byA9IGMoInNhbXBsZSIsICJzdWJzYW1wbGUiKSwgc2VwID0gIl8iKSAlPiUgCiAgbGVmdF9qb2luKGludml0cm9fZGYsIGJ5ID0gInNhbXBsZSIpICU+JSAKICB1bml0ZShzYW1wbGUsIHNhbXBsZSwgc3Vic2FtcGxlLCBzZXAgPSAiXyIpICU+JSAKICBmb3JtYXRfaGxhX3RhYmxlKCkgJT4lIAogIGRyb3BfbmEoKQppbnZpdHJvX2NlbGxzX2RmCmBgYAoKYGBge3J9CiMgSW1wb3J0IHJlYWQgc3RhdGlzdGljcwpzdWJzYW1wbGVfY2VsbHNfYXJjYXNfbG9nX2RpciA8LSBzcHJpbnRmKCIlcy9hcmNhc0hMQSIsIHN1YnNhbXBsZV9jZWxsc19wYXRoKQpzdWJzYW1wbGVfY2VsbHNfYWxpZ25tZW50X3N0YXRzX2RmIDwtIGhsYV9tYXBwaW5nX3N0YXRzX2ltcG9ydChzdWJzYW1wbGVfY2VsbHNfc2FtcGxlcywgc3Vic2FtcGxlX2NlbGxzX2FyY2FzX2xvZ19kaXIpCmBgYAoKYGBge3J9CiMgSW1wb3J0IGNlbGwgY291bnRzIGZvciBlYWNoIHN1YnNhbXBsZQpzdWJzYW1wbGVfY2VsbF9jb3VudHNfZGYgPC0gdGliYmxlKGxpbmUgPSBzeXN0ZW0oIndjIC1sIC9sYWJzL2toYXRyaWxhYi9zb2xvbW9uYi9jb3ZpZC9pc2Ivc3Vic2FtcGxlX2NlbGxzL2JhcmNvZGVzL0lOQ09WKiIsIGludGVybiA9IFQpKSAlPiUgCiAgc2VwYXJhdGUobGluZSwgaW50byA9IGMoIm5fY2VsbHMiLCAiZmlsZSIpLCBzZXAgPSAiIC8iKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBtdXRhdGUoc2FtcGxlID0gZ3N1YigiXFwuLioiLCIiLGJhc2VuYW1lKGZpbGUpKSkgJT4lIAogIG11dGF0ZShuX2NlbGxzID0gYXMubnVtZXJpYyhuX2NlbGxzKSkgJT4lIAogIHNlbGVjdCgtZmlsZSkgJT4lIAogICMgc2VwYXJhdGUoc2FtcGxlLCBpbnRvID0gYygic2FtcGxlIiwgInN1YnNldCIpLCBzZXAgPSAiXyIpICU+JSAKICBiaW5kX3Jvd3MoY2VsbF9jb3VudHNfZGYpCnN1YnNhbXBsZV9jZWxsX2NvdW50c19kZgpgYGAKCiMjIyBDYWxjdWxhdGUgYWNjdXJhY3kKCmBgYHtyfQojIENhbGN1bGF0ZSBhY2N1cmFjeQpzdWJzYW1wbGVfY2VsbHNfYWNjdXJhY3lfZGYgPC0gY29tcGFyZV9obGEoCiAgaGxhX2RmID0gYmluZF9yb3dzKAogICAgc3Vic2FtcGxlX2NlbGxzX2RmLAogICAgaW52aXRyb19jZWxsc19kZgogICksCiAgcmVmZXJlbmNlID0gImludml0cm8iLCAKICBtZXRob2QgPSAiYWNjdXJhY3kiCikKIyBzYXZlUkRTKHN1YnNhbXBsZV9jZWxsc19hY2N1cmFjeV9kZiwgImlzYl9zdWJzYW1wbGVfY2VsbHNfYWNjdXJhY3kuUkRTIikKYGBgCgpgYGB7cn0KIyBDYWxjdWxhdGUgc3VjY2VzcwpzdWJzYW1wbGVfY2VsbHNfc3VjY2Vzc19kZiA8LSBjb21wYXJlX2hsYSgKICBobGFfZGYgPSBiaW5kX3Jvd3MoCiAgICBzdWJzYW1wbGVfY2VsbHNfZGYsCiAgICBpbnZpdHJvX2NlbGxzX2RmCiAgKSwKICByZWZlcmVuY2UgPSAiaW52aXRybyIsIAogIG1ldGhvZCA9ICJzdWNjZXNzIgopCiMgc2F2ZVJEUyhzdWJzYW1wbGVfY2VsbHNfc3VjY2Vzc19kZiwgImlzYl9zdWJzYW1wbGVfY2VsbHNfc3VjY2Vzcy5SRFMiKQpgYGAKCmBgYHtyfQojIENvbWJpbmUgdmFyaW91cyBkYXRhCnN1YnNhbXBsZV9jZWxsc19jb21iaW5lZF9kZiA8LSBzdWJzYW1wbGVfY2VsbHNfYWNjdXJhY3lfZGYgJT4lIAogIGxlZnRfam9pbigKICAgIHN1YnNhbXBsZV9jZWxsc19zdWNjZXNzX2RmICU+JSBzZWxlY3Qoc2FtcGxlOmZpZWxkLCBnZW5vdHlwZXIsIHN1Y2Nlc3MgPSBhY2N1cmFjeSksCiAgICBieSA9IGMoInNhbXBsZSIsICJsb2N1cyIsICJmaWVsZCIsICJnZW5vdHlwZXIiKQogICklPiUgCiAgbGVmdF9qb2luKHN1YnNhbXBsZV9jZWxsc19hbGlnbm1lbnRfc3RhdHNfZGYsIGJ5ID0gYygic2FtcGxlIiwgImxvY3VzIikpICU+JSAKICBsZWZ0X2pvaW4oZ2Vub21lX3JlZ2lvbl9yZWZlcmVuY2UsIGJ5ID0gImxvY3VzIikgJT4lCiAgbGVmdF9qb2luKHN1YnNhbXBsZV9jZWxsX2NvdW50c19kZiwgYnkgPSAic2FtcGxlIikgJT4lCiAgYmluZF9yb3dzKGFjY3VyYWN5X2RmKSAlPiUgCiAgbXV0YXRlX2F0KHZhcnMoYyhyZWFkcywgYnApKSwgYXMubnVtZXJpYykgJT4lIAogIG11dGF0ZShjb3ZlcmFnZSA9IChyZWFkcyAqIDkxKS9icCkgJT4lIAogIG11dGF0ZShuX2FsbGVsZXMgPSBtYXBfZGJsKGFsbGVsZSwgZnVuY3Rpb24oeCkgc3VtKCFpcy5uYSh4KSkpKSAlPiUgCiAgZmlsdGVyKGdyZXBsKCJeW0FCQ118RC5bQUJdMSIsIGxvY3VzKSAmIGdyZXBsKCItKEFDfEJMKSIsIHNhbXBsZSkgJiBnZW5vdHlwZXIgIT0gImhsYW1pbmVyIikgCmBgYAoKIyMjIENvdmVyYWdlIHBsb3RzCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTIuNSwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQpnZ19jb3ZlcmFnZShzdWJzYW1wbGVfY2VsbHNfY29tYmluZWRfZGYsIHhfdmFyID0gImNvdmVyYWdlIiwgeV92YXIgPSAiYWNjdXJhY3kiKSAKYGBgCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Mi41LCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9CmdnX2NvdmVyYWdlKHN1YnNhbXBsZV9jZWxsc19jb21iaW5lZF9kZiwgeF92YXIgPSAiY292ZXJhZ2UiLCB5X3ZhciA9ICJzdWNjZXNzIikKYGBgCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Mywgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQpnZ19jb3ZlcmFnZShzdWJzYW1wbGVfY2VsbHNfY29tYmluZWRfZGYsIHhfdmFyID0gImNvdmVyYWdlIiwgeV92YXIgPSAibl9hbGxlbGVzIiwgZmFjZXRfZ2Vub3R5cGVyID0gVCkKYGBgCgojIyMgQ2VsbCBudW1iZXIgcGxvdHMKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Mi41LCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9CmdnX2NvdmVyYWdlKHN1YnNhbXBsZV9jZWxsc19jb21iaW5lZF9kZiwgeF92YXIgPSAibl9jZWxscyIsIHlfdmFyID0gImFjY3VyYWN5IikgCnBsdF9jZWxsX2FjY3VyYWN5X2FsbCA8LSBnZ19jb3ZlcmFnZShzdWJzYW1wbGVfY2VsbHNfY29tYmluZWRfZGYsIHhfdmFyID0gIm5fY2VsbHMiLCB5X3ZhciA9ICJhY2N1cmFjeSIpIApwbHRfY2VsbF9hY2N1cmFjeV9hYmMgPC0gZ2dfY292ZXJhZ2Uoc3Vic2FtcGxlX2NlbGxzX2NvbWJpbmVkX2RmICU+JSBmaWx0ZXIoZ3JlcGwoIl5bQUJDXSIsIGxvY3VzKSksIHhfdmFyID0gIm5fY2VsbHMiLCB5X3ZhciA9ICJhY2N1cmFjeSIpIApgYGAKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0yLjUsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0KZ2dfY292ZXJhZ2Uoc3Vic2FtcGxlX2NlbGxzX2NvbWJpbmVkX2RmLCB4X3ZhciA9ICJuX2NlbGxzIiwgeV92YXIgPSAic3VjY2VzcyIpIApwbHRfY2VsbF9zdWNjZXNzX2FsbCA8LSBnZ19jb3ZlcmFnZShzdWJzYW1wbGVfY2VsbHNfY29tYmluZWRfZGYsIHhfdmFyID0gIm5fY2VsbHMiLCB5X3ZhciA9ICJzdWNjZXNzIikgCnBsdF9jZWxsX3N1Y2Nlc3NfYWJjIDwtIGdnX2NvdmVyYWdlKHN1YnNhbXBsZV9jZWxsc19jb21iaW5lZF9kZiAlPiUgZmlsdGVyKGdyZXBsKCJeW0FCQ10iLCBsb2N1cykpLCB4X3ZhciA9ICJuX2NlbGxzIiwgeV92YXIgPSAic3VjY2VzcyIpIApgYGAKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0zLCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9CmdnX2NvdmVyYWdlKHN1YnNhbXBsZV9jZWxsc19jb21iaW5lZF9kZiwgeF92YXIgPSAibl9jZWxscyIsIHlfdmFyID0gIm5fYWxsZWxlcyIsIGZhY2V0X2dlbm90eXBlciA9IFQpCnBsdF9jZWxsX2FsbGVsZV9hbGwgPC0gZ2dfY292ZXJhZ2Uoc3Vic2FtcGxlX2NlbGxzX2NvbWJpbmVkX2RmLCB4X3ZhciA9ICJuX2NlbGxzIiwgeV92YXIgPSAibl9hbGxlbGVzIiwgZmFjZXRfZ2Vub3R5cGVyID0gVCkKcGx0X2NlbGxfYWxsZWxlX2FiYyA8LSBnZ19jb3ZlcmFnZShzdWJzYW1wbGVfY2VsbHNfY29tYmluZWRfZGYgJT4lIGZpbHRlcihncmVwbCgiXltBQkNdIiwgbG9jdXMpKSwgeF92YXIgPSAibl9jZWxscyIsIHlfdmFyID0gIm5fYWxsZWxlcyIsIGZhY2V0X2dlbm90eXBlciA9IFQpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Mywgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQojIHN1YnNhbXBsZV9jZWxsc19jb21iaW5lZF9kZiAlPiUgCiMgICBtdXRhdGUocmVhZHMgPSByZWFkcy9uX2NlbGxzKSAlPiUgCiMgICBmaWx0ZXIocmVhZHMgPCAxMDApICU+JSAKIyAgIGdnX2NvdmVyYWdlKHhfdmFyID0gInJlYWRzIiwgeV92YXIgPSAiYWNjdXJhY3kiLCB4X2xvZyA9IEYpIApgYGAKCgoKCgoKCgojIENvbWJpbmVkIHBsb3RzCmBgYHtyLCBmaWcud2lkdGggPSA5LCBmaWcuaGVpZ2h0ID0gNywgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGfQpub19sZWcgPC0gbGlzdCh0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKQpsZWdlbmQgPC0gY293cGxvdDo6Z2V0X2xlZ2VuZChwbHRfcmVhZF9hY2N1cmFjeV9hYmMpCnBsb3RfZ3JpZCgKICBwbG90X2dyaWQoCiAgICBwbHRfcmVhZF9hY2N1cmFjeV9hYmMgKyBub19sZWcsCiAgICBwbHRfcmVhZF9zdWNjZXNzX2FiYyArIG5vX2xlZywKICAgIHBsdF9yZWFkX2FsbGVsZV9hYmMsCiAgICBuY29sID0gMSwKICAgIGFsaWduID0gInYiLAogICAgYXhpcyA9ICJsciIsCiAgICByZWxfaGVpZ2h0cyA9IGMoMSwxLDEuMiksCiAgICBsYWJlbHMgPSBMRVRURVJTWzE6M10KICApLAogIHBsb3RfZ3JpZCgKICAgIHBsdF9jZWxsX2FjY3VyYWN5X2FiYyArIG5vX2xlZywKICAgIHBsdF9jZWxsX3N1Y2Nlc3NfYWJjICsgbm9fbGVnLAogICAgcGx0X2NlbGxfYWxsZWxlX2FiYywKICAgIG5jb2wgPSAxLAogICAgYWxpZ24gPSAidiIsCiAgICBheGlzID0gImxyIiwKICAgIHJlbF9oZWlnaHRzID0gYygxLDEsMS4yKSwKICAgIGxhYmVscyA9IExFVFRFUlNbNDo2XQogICksCiAgcGxvdF9ncmlkKAogICAgbGVnZW5kLAogICAgbGVnZW5kLAogICAgTkEsCiAgICBuY29sID0gMQogICksCiAgbnJvdyA9IDEsCiAgcmVsX3dpZHRocyA9IGMoMSwxLDAuMjUpCikKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gMTgsIGZpZy5oZWlnaHQgPSA3LCBtZXNzYWdlID0gRiwgd2FybmluZyA9IEZ9Cm5vX2xlZyA8LSBsaXN0KHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmxlZ2VuZCA8LSBjb3dwbG90OjpnZXRfbGVnZW5kKHBsdF9yZWFkX2FjY3VyYWN5X2FsbCkKcGxvdF9ncmlkKAogIHBsb3RfZ3JpZCgKICAgIHBsdF9yZWFkX2FjY3VyYWN5X2FsbCArIG5vX2xlZywKICAgIHBsdF9yZWFkX3N1Y2Nlc3NfYWxsICsgbm9fbGVnLAogICAgcGx0X3JlYWRfYWxsZWxlX2FsbCwKICAgIG5jb2wgPSAxLAogICAgYWxpZ24gPSAidiIsCiAgICBheGlzID0gImxyIiwKICAgIHJlbF9oZWlnaHRzID0gYygxLDEsMS4yKSwKICAgIGxhYmVscyA9IExFVFRFUlNbMTozXQogICksCiAgcGxvdF9ncmlkKAogICAgcGx0X2NlbGxfYWNjdXJhY3lfYWxsICsgbm9fbGVnLAogICAgcGx0X2NlbGxfc3VjY2Vzc19hbGwgKyBub19sZWcsCiAgICBwbHRfY2VsbF9hbGxlbGVfYWxsLAogICAgbmNvbCA9IDEsCiAgICBhbGlnbiA9ICJ2IiwKICAgIGF4aXMgPSAibHIiLAogICAgcmVsX2hlaWdodHMgPSBjKDEsMSwxLjIpLAogICAgbGFiZWxzID0gTEVUVEVSU1s0OjZdCiAgKSwKICBwbG90X2dyaWQoCiAgICBsZWdlbmQsCiAgICBsZWdlbmQsCiAgICBOQSwKICAgIG5jb2wgPSAxCiAgKSwKICBucm93ID0gMSwKICByZWxfd2lkdGhzID0gYygxLDEsMC4yNSkKKQpgYGAKCiMgU2xvcGUgc3RhdHMKCmBgYHtyfQpnZXRfbG1fc3RhdHMgPC0gZnVuY3Rpb24oZGYsIHhfdmFyID0gImNvdmVyYWdlIiwgeV92YXIgPSAiYWNjdXJhY3kiLCBmaWVsZF92YXIgPSAiZmllbGRfMiIsIHhfbG9nID0gVCl7CiAgIyBJbnB1dCBjaGVja3MKICBhcmdfY29sIDwtIG1ha2VBc3NlcnRDb2xsZWN0aW9uKCkKICBhc3NlcnRDaG9pY2UoeV92YXIsIGMoImFjY3VyYWN5IiwgInN1Y2Nlc3MiLCAibl9hbGxlbGVzIiksIGFkZCA9IGFyZ19jb2wpCiAgYXNzZXJ0Q2hvaWNlKHhfdmFyLCBjKCJyZWFkcyIsICJjb3ZlcmFnZSIsICJuX2NlbGxzIiksIGFkZCA9IGFyZ19jb2wpCiAgYXNzZXJ0Q2hvaWNlKGZpZWxkX3ZhciwgYygiZmllbGRfMSIsICJmaWVsZF8yIiwgImZpZWxkXzMiKSwgYWRkID0gYXJnX2NvbCkKICBhc3NlcnRMb2dpY2FsKHhfbG9nLCBhZGQgPSBhcmdfY29sKQogIGlmIChhcmdfY29sJGlzRW1wdHkoKT09Rikge21hcChhcmdfY29sJGdldE1lc3NhZ2VzKCkscHJpbnQpO3JlcG9ydEFzc2VydGlvbnMoYXJnX2NvbCl9CiAgCiAgIyBicm93c2VyKCkKICBkZiA8LSBkZiAlPiUgCiAgICBmaWx0ZXIoZmllbGQgPT0gZmllbGRfdmFyKSAlPiUgCiAgICByZW1vdmVfaW52YWxpZF9jb21iaW5hdGlvbnMoKQogIGlmICh4X2xvZyA9PVQpe2RmIDwtIGRmICU+JSBtdXRhdGVfYXQoeF92YXIsIGxvZzEwKX0KICBkZiAlPiUKICBmaWx0ZXJfYXQoeF92YXIsIGZ1bmN0aW9uKHgpICFpcy5uYSh4KSAmICFpcy5pbmZpbml0ZSh4KSkgJT4lIAogIGdyb3VwX2J5KGxvY3VzLCBmaWVsZCwgZ2Vub3R5cGVyKSAlPiUKICBuZXN0KCkgJT4lCiAgbXV0YXRlKGRhdGEgPSBtYXAoZGF0YSwgZnVuY3Rpb24oeCl7CiAgICBzdW1tYXJ5KGxtKCEhc3ltKHlfdmFyKSB+ICEhc3ltKHhfdmFyKSwgZGF0YSA9IHgpKSAlPiUgYnJvb206OnRpZHkoKSAlPiUgZmlsdGVyKHRlcm0gPT0geF92YXIpCiAgfSkpICU+JSB1bm5lc3Rfd2lkZXIoZGF0YSkgJT4lCiAgbXV0YXRlKGVzdF9taW4gPSByb3VuZChlc3RpbWF0ZSAtIDIqc3RkLmVycm9yLCAyKSwKICAgICAgICAgZXN0X21heCA9IHJvdW5kKGVzdGltYXRlICsgMipzdGQuZXJyb3IsIDIpKQp9Cgptb2RlbF9zdGF0cyA8LSBnZXRfbG1fc3RhdHMoc3Vic2FtcGxlX2NlbGxzX2NvbWJpbmVkX2RmLCB4X3ZhciA9ICJyZWFkcyIsIHlfdmFyID0gImFjY3VyYWN5IiwgeF9sb2cgPSBUKQptb2RlbF9zdGF0cwpgYGAKCmBgYHtyfQptb2RlbF9zdGF0cyA8LSBiaW5kX3Jvd3MoCiAgZ2V0X2xtX3N0YXRzKHN1YnNhbXBsZV9yZWFkc19jb21iaW5lZF9kZiwgeF92YXIgPSAicmVhZHMiLCB5X3ZhciA9ICJhY2N1cmFjeSIsIHhfbG9nID0gVCkgJT4lIG11dGF0ZSh4X3ZhciA9ICJyZWFkcyIsIHlfdmFyID0gImFjY3VyYWN5IiksCiAgZ2V0X2xtX3N0YXRzKHN1YnNhbXBsZV9yZWFkc19jb21iaW5lZF9kZiwgeF92YXIgPSAicmVhZHMiLCB5X3ZhciA9ICJzdWNjZXNzIiwgeF9sb2cgPSBUKSAlPiUgbXV0YXRlKHhfdmFyID0gInJlYWRzIiwgeV92YXIgPSAic3VjY2VzcyIpLAogIGdldF9sbV9zdGF0cyhzdWJzYW1wbGVfY2VsbHNfY29tYmluZWRfZGYsIHhfdmFyID0gIm5fY2VsbHMiLCB5X3ZhciA9ICJhY2N1cmFjeSIsIHhfbG9nID0gVCkgJT4lIG11dGF0ZSh4X3ZhciA9ICJjZWxscyIsIHlfdmFyID0gImFjY3VyYWN5IiksCiAgZ2V0X2xtX3N0YXRzKHN1YnNhbXBsZV9jZWxsc19jb21iaW5lZF9kZiwgeF92YXIgPSAibl9jZWxscyIsIHlfdmFyID0gInN1Y2Nlc3MiLCB4X2xvZyA9IFQpICU+JSBtdXRhdGUoeF92YXIgPSAiY2VsbHMiLCB5X3ZhciA9ICJzdWNjZXNzIikKKSAgJT4lIAogICMgZmlsdGVyKGdyZXBsKCJeW0FCQ10iLCBsb2N1cykpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGZpbHRlcihmaWVsZCA9PSAiZmllbGRfMiIpIApgYGAKCgoKIyBUYWJsZQpgYGB7cn0KY29sX3ZhcnMgPC0gYygieF92YXIiLCAibG9jdXMiKQpyb3dfdmFycyA8LSBjKCJ5X3ZhciIsICJnZW5vdHlwZXIiKQoKZmxleF9kZiA8LSBtb2RlbF9zdGF0cyAlPiUgCiAgIyBmaWx0ZXIoZ3JlcGwoIl5bQUJDXSIsIGxvY3VzKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKGZpZWxkID09ICJmaWVsZF8yIikgJT4lIAogIG11dGF0ZShDSSA9IHNwcmludGYoIiglcykgLSAoJXMpIiwgZXN0X21pbiwgZXN0X21heCkpICU+JSAKICBtdXRhdGUoZ2Vub3R5cGVyID0gcmVmb3JtYXRfaGxhX2dlbm90eXBlcihnZW5vdHlwZXIpKSAlPiUgCiAgc2VsZWN0KGdlbm90eXBlciwgbG9jdXMsIENJLCB4X3ZhciwgeV92YXIpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY29sX3ZhcnMsIHZhbHVlc19mcm9tID0gIkNJIiwgbmFtZXNfc2VwID0gICItIikgCgpkZl9rZXkgPC0gdGliYmxlKGNvbF9rZXlzID0gbmFtZXMoZmxleF9kZikpICU+JSAKICBmaWx0ZXIoIShjb2xfa2V5cyAlaW4lIGMoY29sX3ZhcnMsIHJvd192YXJzKSkpICU+JSAKICBzZXBhcmF0ZShjb2xfa2V5cywgaW50byA9IGNvbF92YXJzLCBzZXAgPSAiLSIsIHJlbW92ZSA9IEYpICU+JQogIG11dGF0ZV9hdCh2YXJzKGNvbnRhaW5zKCJnZW5vdHlwZXIiKSksIHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIpICU+JSAKICBhcnJhbmdlX2F0KGNvbF92YXJzKSAlPiUgCiAgbXV0YXRlX2FsbChhcy5jaGFyYWN0ZXIpICU+JSAKICBtdXRhdGVfYXQoY29sX3ZhcnNbIShjb2xfdmFycyAlaW4lICJsb2N1cyIpXSwgc3RyX3RvX3NlbnRlbmNlKQoKZmxleF9kZiAlPiUgCiAgc2VsZWN0KHJvd192YXJzLCBldmVyeXRoaW5nKCkpICU+JSAKICBtdXRhdGVfYXQocm93X3ZhcnNbIShyb3dfdmFycyAlaW4lICJnZW5vdHlwZXIiKV0sIHN0cl90b19zZW50ZW5jZSkgJT4lIAogICMgc2VsZWN0KGxvY3VzLCBkZl9rZXkkY29sX2tleXMpICU+JSAKICBmbGV4dGFibGUoKSAlPiUgCiAgY29sZm9ybWF0X2NoYXIobmFfc3RyID0gIi0tLSIpICU+JQogIG1lcmdlX3Yoaj0xOjIpICU+JSAKICBzZXRfaGVhZGVyX2RmKG1hcHBpbmcgPSBkZl9rZXksIGtleSA9ICJjb2xfa2V5cyIpICU+JSAKICBtZXJnZV9oKHBhcnQgPSAiaGVhZGVyIikgJT4lCiAgdGhlbWVfdmFuaWxsYSgpICU+JSAKICAjIHZsaW5lKGo9dmxpbmVzX3NlcXVlbmNlLCBib3JkZXIgPSBmcF9ib3JkZXJfZGVmYXVsdCgpKSAlPiUKICBmaXhfYm9yZGVyX2lzc3VlcygpICU+JSAKICBhdXRvZml0KCkgJT4lIAogIGZvbnRzaXplKHNpemUgPSA4LCBwYXJ0ID0gImFsbCIpICU+JSAKICBwcmludChwcmV2aWV3ID0gInBwdHgiKQpgYGAKCgpgYGB7cn0KICBkZiA8LSBkZiAlPiUgCiAgICBtdXRhdGUoZmllbGQgPSByZWZvcm1hdF9obGFfZmllbGQoZmllbGQpKSAlPiUgCiAgICBtdXRhdGVfYXQodmFycyhjb250YWlucygiZ2Vub3R5cGVyIikpLCByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKSAlPiUgCiAgICBtdXRhdGUoY2VsbF92YWx1ZSA9IGlmZWxzZSghaXMubmEoc2UpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoIiVzICVzICVzIiwgcm91bmQobWVhbl9hY2N1cmFjeSwyKSwiXHUwMEIxIixyb3VuZChzZSwyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCIlcyIsIHJvdW5kKG1lYW5fYWNjdXJhY3ksMikpKSkgJT4lCiAgICBtdXRhdGUoY2VsbF92YWx1ZSA9IGlmZWxzZShncmVwbCgiTkEiLCBjZWxsX3ZhbHVlKSwgTkEsIGNlbGxfdmFsdWUpKSAlPiUgCiAgICBzZWxlY3QoLXNkLC1zZSwgLW1lYW5fYWNjdXJhY3kpICU+JSAKICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBuZXN0aW5nX3ZhcnMsIHZhbHVlc19mcm9tID0gImNlbGxfdmFsdWUiLCBuYW1lc19zZXAgPSAiLSIpIAogIAogIGRmX2tleSA8LSBzdXBwcmVzc1dhcm5pbmdzKHt0aWJibGUoY29sX2tleXMgPSBuYW1lcyhkZikpICU+JSAKICAgICAgZmlsdGVyKCFncmVwbCgibG9jdXMiLCBjb2xfa2V5cykpICU+JSAKICAgICAgc2VwYXJhdGUoY29sX2tleXMsIGludG8gPSBuZXN0aW5nX3ZhcnMsIHNlcCA9ICItIiwgcmVtb3ZlID0gRikgJT4lCiAgICAgIG11dGF0ZV9hdCh2YXJzKGNvbnRhaW5zKCJnZW5vdHlwZXIiKSksIHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIpICU+JSAKICAgICAgYXJyYW5nZV9hdChuZXN0aW5nX3ZhcnMpICU+JSAKICAgICAgbXV0YXRlX2FsbChhcy5jaGFyYWN0ZXIpCiAgfSkKICAKICB2bGluZV92YXIgPC0gdGFpbChuZXN0aW5nX3ZhcnMsMSkKICB2bGluZXNfc2VxdWVuY2UgPC0gc2VxKDEsbnJvdyhkZl9rZXkpLGJ5ID0gbGVuZ3RoKHVuaXF1ZShkZl9rZXlbW3ZsaW5lX3Zhcl1dKSkpCiAgZGYgPC0gZGYgJT4lIAogICAgc2VsZWN0KGxvY3VzLCBkZl9rZXkkY29sX2tleXMpICU+JSAKICAgIGZsZXh0YWJsZSgpICU+JSAKICAgIGNvbGZvcm1hdF9jaGFyKG5hX3N0ciA9ICItLS0iKSAlPiUgCiAgICBzZXRfaGVhZGVyX2RmKG1hcHBpbmcgPSBkZl9rZXksIGtleSA9ICJjb2xfa2V5cyIpICU+JSAKICAgIG1lcmdlX2gocGFydCA9ICJoZWFkZXIiKSAlPiUgCiAgICB0aGVtZV92YW5pbGxhKCkgJT4lIAogICAgdmxpbmUoaj12bGluZXNfc2VxdWVuY2UsIGJvcmRlciA9IGZwX2JvcmRlcl9kZWZhdWx0KCkpICU+JQogICAgZml4X2JvcmRlcl9pc3N1ZXMoKQogIHJldHVybihkZikKYGBgCgoKCgoKIyBTY3JhdGNoIHdvcmsKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Mywgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQpzdWJzYW1wbGVfY2VsbHNfY29tYmluZWRfZGYgJT4lIAogIGZpbHRlcihmaWVsZCA9PSAiZmllbGRfMiIpICU+JSAKICBtdXRhdGUobl9hbGxlbGVzID0gZmFjdG9yKG5fYWxsZWxlcywgbGV2ZWxzID0gMDoyKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IG5fYWxsZWxlcywgeSA9IGxvZzEwKG5fY2VsbHMpKSkrCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiKSsKICBnZW9tX2ppdHRlcihzaXplID0gMC4yLCBoZWlnaHQgPSAwLCB3aWR0aCA9MC4wNSwgYWxwaGEgPSAwLjIpKwogICMgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMSkrCiAgIyBnZ2JlZXN3YXJtOjpnZW9tX2JlZXN3YXJtKHNpemUgPSAwLjEsIGFscGhhID0gMC4xKSsKICBjb29yZF9mbGlwKCkrCiAgZmFjZXRfZ3JpZChnZW5vdHlwZXIgfiBsb2N1cywgc2NhbGVzID0gImZyZWUiKSsKICB0aGVtZV9idygpCmBgYAojIENvdmVyYWdlIHN0YXRzCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Mywgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQpzdWJzYW1wbGVfY2VsbHNfY29tYmluZWRfZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IG5fY2VsbHMsIHkgPSBjb3ZlcmFnZSwgY29sb3IgPSBnZW5vdHlwZXIpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfd3JhcChnZW5vdHlwZXIgfiBsb2N1cywgc2NhbGVzID0gImZyZWUiLCBucm93ID0gMykgKyAKICB0aGVtZV9idygpICsKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTMsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0Kc3Vic2FtcGxlX2NlbGxzX2NvbWJpbmVkX2RmICU+JSAKICBzZWxlY3QoLWdlbm90eXBlcikgJT4lIGRpc3RpbmN0KCkgJT4lIAogIG11dGF0ZShjb3ZfcGVyX2NlbGwgPSBjb3ZlcmFnZS9uX2NlbGxzKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbG9nMTAobl9jZWxscyksIHkgPSBjb3ZfcGVyX2NlbGwpKSArIAogIGdlb21fcG9pbnQoY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuMSkgKwogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIpKwogICMgc3RhdF9zbW9vdGgoKSsKICAgIGZhY2V0X3dyYXAoIH4gbG9jdXMsIHNjYWxlcyA9ICJmcmVlIiwgbnJvdyA9IDEpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD02LCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9CnN1YnNhbXBsZV9jZWxsc19jb21iaW5lZF9kZiAlPiUgCiAgc2VsZWN0KC1nZW5vdHlwZXIpICU+JSBkaXN0aW5jdCgpICU+JSAKICBmaWx0ZXIoIWlzLm5hKG5fY2VsbHMpKSAlPiUgCiAgbXV0YXRlKGNvdl9wZXJfY2VsbCA9IGNvdmVyYWdlL25fY2VsbHMpICU+JSAKICBtdXRhdGUobl9jZWxscyA9IGN1dChuX2NlbGxzLCBzZXEoMCwxMDAwMCxieT0yNTAwKSwgcmlnaHQgPSBGKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IG5fY2VsbHMsIHkgPSBjb3ZfcGVyX2NlbGwpKSArIAogIHN0YXRfc3VtbWFyeShmdW4gPSBmdW5jdGlvbih4KSBtZWFuKHgsbmEucm09VCksIGdlb20gPSAiYmFyIikgKwogICMgZ2VvbV9wb2ludChjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC4xKSArCiAgIyBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iKSsKICAjIHN0YXRfc21vb3RoKCkrCiAgZmFjZXRfd3JhcCggfiBsb2N1cywgc2NhbGVzID0gImZyZWUiLCBucm93ID0gMSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikKYGBgCgpgYGB7cn0KaGlzdChjdXQoMToxMDAsIHNlcSgxLDEwMCwxMCkpKQpgYGAKCmBgYHtyfQpzdWJzYW1wbGVfY2VsbHNfY29tYmluZWRfZGYgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgY291bnQoZ2Vub3R5cGVyLCBsb2N1cywgZmllbGQpCmBgYApgYGB7cn0Kc3Vic2FtcGxlX3JlYWRzX2NvbWJpbmVkX2RmICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGNvdW50KGdlbm90eXBlciwgbG9jdXMsIGZpZWxkKQpgYGAK